//
// This software is now distributed according to
// the Lesser Gnu Public License. Please see
// http://www.gnu.org/copyleft/lesser.txt for
// the details.
// -- Happy Computing!
//
package com.stevesoft.pat;

import java.util.Hashtable;

/**
 * A special optimization of multi that is used when the common subpattern ".*"
 * is encountered.
 */
class DotMulti extends PatternSub {

	patInt fewestMatches, mostMatches;

	public patInt minChars() {
		return fewestMatches;
	}

	public patInt maxChars() {
		return mostMatches;
	}

	public boolean matchFewest = false;
	StringLike src = null;
	int srclength = 0;
	boolean dotDoesntMatchCR = true;

	DotMulti(patInt a, patInt b) {
		fewestMatches = a;
		mostMatches = b;
	}

	public String toString() {
		return ".{" + fewestMatches + "," + mostMatches + "}" + (matchFewest ? "?" : "") + "(?# <= dot multi)"
				+ nextString();
	}

	final int submatchInternal(int pos, Pthings pt) {
		if (pos < srclength) {
			if (dotDoesntMatchCR) {
				if (src.charAt(pos) != '\n')
					return 1 + pos;
			}
			else
				return 1 + pos;
		}
		return -1;
	}

	final static int step = 1;
	static int idcount = 1;

	public int matchInternal(int pos, Pthings pt) {
		int m = -1;
		int i = pos;
		src = pt.src;
		srclength = src.length();
		dotDoesntMatchCR = pt.dotDoesntMatchCR;
		if (matchFewest) {
			int nMatches = 0;
			while (fewestMatches.intValue() > nMatches) {
				i = submatchInternal(i, pt);
				if (i < 0)
					return -1;
				nMatches++;
			}
			if (i < 0)
				return -1;
			int ii = nextMatch(i, pt);
			if (ii >= 0)
				return ii;
			if (!mostMatches.finite()) {
				while (i >= 0) {
					i = submatchInternal(i, pt);
					if (i < 0)
						return -1;
					ii = nextMatch(i, pt);
					if (ii >= 0)
						return ii;
				}
			}
			else {
				while (i > 0) {
					i = submatchInternal(i, pt);
					if (i < 0)
						return -1;
					nMatches++;
					if (nMatches > mostMatches.intValue())
						return -1;
					ii = nextMatch(i, pt);
					if (ii >= 0)
						return ii;
				}
			}
			return -1;
		}
		int nMatches = 0;
		while (fewestMatches.intValue() > nMatches) {
			i = submatchInternal(i, pt);
			if (i >= 0)
				nMatches++;
			else
				return -1;
		}
		m = i;
		if (mostMatches.finite()) {
			while (nMatches < mostMatches.intValue()) {
				i = submatchInternal(i, pt);
				if (i >= 0) {
					m = i;
					nMatches++;
				}
				else
					break;
			}
		}
		else {
			while (true) {
				i = submatchInternal(i, pt);
				if (i >= 0) {
					m = i;
					nMatches++;
				}
				else
					break;
			}
		}
		while (m >= pos) {
			int r = nextMatch(m, pt);
			if (r >= 0)
				return r;
			m -= step;
			nMatches--;
			if (nMatches < fewestMatches.intValue())
				return -1;
		}
		return -1;
	}

	Pattern clone1(Hashtable h) {
		DotMulti dm = new DotMulti(fewestMatches, mostMatches);
		dm.matchFewest = matchFewest;
		return dm;
	}
}
